%include "boot.inc"
section loader vstart=LOADER_BASE_ADDR
LOADER_STACK_TOP equ LOADER_BASE_ADDR
jmp loader_start
;构建gdt及其内部的描述符
    GDT_BASE:   dd  0x00000000
                dd  0x00000000
    CODE_DESC:  dd  0x0000FFFF
                dd  DESC_CODE_HIGH4
    DATA_STACK_DESC:dd 0x0000FFFF
                    dd DESC_DATA_HIGH4
    ;B0000 B7FFF 32KB 黑白显示适配器
    VIDEO_DESC: dd  0x80000007;limit=(0xbffff-0xb8000)/4k=0x7
                dd  DESC_VIDEO_HIGH4
    GDT_SIZE    equ $-GDT_BASE
    GDT_LIMIT   equ GDT_SIZE-1
    SELECTOR_CODE equ (0x0001<<3)+TI_GDT+RPL0
    SELECTOR_DATA equ (0x0002<<3)+TI_GDT+RPL0
    SELECTOR_VIDEO equ (0x0003<<3)+TI_GDT+RPL0
    times 60 dq 0;预留60个描述符空位
   
	total_mem_bytes dd 0

     gdt_ptr dw GDT_LIMIT
            dd GDT_BASE

	ards_buf times 244 db 0
	ards_nr dw 0

     loadermsg db '2 loader in real.'

loader_start:
	xor ebx,ebx
	mov edx,0x534d4150
	mov di,ards_buf
.e820_mem_get_loop:
	mov eax,0x0000e820
	mov ecx,20
	int 0x15
	jc .e820_failed_so_try_e801

	add di,cx
	inc word [ards_nr] ;add number of ards
	cmp ebx,0

	jnz .e820_mem_get_loop

	mov cx,[ards_nr]
	mov ebx,ards_buf
	xor edx,edx
.find_max_mem_area:
	mov eax,[ebx]
	add eax,[ebx+8]
	add ebx,20
	cmp edx,eax

	jge .next_ards
	mov edx,eax
.next_ards:
	loop .find_max_mem_area
	jmp .mem_get_ok

.e820_failed_so_try_e801:
	mov ax,0xe801
	int 0x15
	jc .e801_failed_so_try88
	
	mov cx,0x400
	mul cx
	shl edx,16
	and eax,0x0000FFFF
	or edx,eax
	add edx,0x100000
	mov esi,edx

	xor eax,eax
	mov ax,bx
	mov ecx,0x10000
	mul ecx
	add esi,eax

	mov edx,esi
	jmp .mem_get_ok

.e801_failed_so_try88:
	mov ah,0x88
	int 0x15
	jc .error_hlt
	and eax,0x0000FFFF
	mov cx,0x400
	mul cx
	shl edx,16
	or edx,eax
	add edx,0x100000
.error_hlt:
	jmp $
.mem_get_ok:
	mov [total_mem_bytes],edx

	

; -----------------------------------------------------------
;INT 0x10   功能号:0x13	   功能描述:打印字符串
;------------------------------------------------------
;输入：
;AH 功能号= 0x13H
;BH = 页码
;BL = 属性(若AL=00H或01H)
;CX = 字符串长度
;ES:BP=字符串地址
;AL=输出方式
;   0——字符串中只含显示字符，其显示属性在BL中。显示后，光标位置不变
;   1——字符串中只含显示字符，其显示属性在BL中。显示后，光标位置改变
;   2——字符串中含显示字符和显示属性。显示后，光标位置不变
;   3——字符串中含显示字符和显示属性。显示后，光标位置改变
;无返回值

    mov sp,LOADER_BASE_ADDR
    mov bp,loadermsg
    mov cx,17
    mov ax,0x1301           ;AH=13,AL=01
    mov bx,0x001f           ;页号为0,蓝底粉红字(BL=1fh)
    mov dx,0x1800
    int 0x10                ;10h号中断

;-------- 准备进入保护模式 --------    
;1：打开A20
;2：加载gdt
;3：将cr0的pe位置1

    ;-------- 打开A20 --------
    in al,0x92
    or al,0000_0010B
    out 0x92,al

    ;-------- 加载GDT --------
    lgdt [gdt_ptr]

    ;-------- 将cr0的pe位置1 --------
    mov eax,cr0
    or eax,0x00000001
    mov cr0,eax

    jmp dword SELECTOR_CODE:p_mode_start;刷新流水线

[bits 32]
p_mode_start:
    mov ax,SELECTOR_DATA
    mov ds,ax
    mov es,ax
    mov ss,ax
    mov esp,LOADER_STACK_TOP
    mov ax,SELECTOR_VIDEO
    mov gs,ax

    mov byte[gs:160],'p'
    mov byte[gs:161],0x1f

call setup_page

sgdt [gdt_ptr]

mov ebx,[gdt_ptr + 2]
or dword [ebx + 0x18 + 4],0xc0000000
add dword [gdt_ptr + 2],0xc0000000
add esp,0xc0000000
mov eax,PAGE_DIR_TABLE_POS
mov cr3,eax

mov eax,cr0
or eax,0x80000000
mov cr0,eax

lgdt [gdt_ptr]

mov byte [gs:160],'V'

jmp $

;create_PDE
setup_page:
	mov ecx,4096
	mov esi,0
.clear_page_dir:
	mov byte [PAGE_DIR_TABLE_POS + esi],0
	inc esi
	loop .clear_page_dir

.create_pde:
	mov eax,PAGE_DIR_TABLE_POS
	add eax,0x1000
	mov ebx,eax
	
	or eax,PG_US_U | PG_RW_W | PG_P
	mov [PAGE_DIR_TABLE_POS + 0x0],eax
	mov [PAGE_DIR_TABLE_POS + 0xc00],eax
	sub eax,0x1000
	mov [PAGE_DIR_TABLE_POS + 4092],eax

;create_PTE
	mov ecx,256
	mov esi,0
	mov edx,PG_US_U | PG_RW_W | PG_P
.create_pte:
	mov [ebx+esi*4],edx
	add edx,4096
	inc esi
	loop .create_pte
	
	mov eax,PAGE_DIR_TABLE_POS
	add eax,0x2000
	or eax,PG_US_U | PG_RW_W | PG_P
	mov ebx,PAGE_DIR_TABLE_POS
	mov ecx,254
	mov esi,769
.create_kernel_pde:
	mov [ebx+esi*4],eax
	inc esi
	add eax,0x1000
	loop .create_kernel_pde
	ret

